libobs_simple\sources\windows\sources/
window_capture.rs

1use crate::define_object_manager;
2
3use super::{ObsWindowCaptureMethod, ObsWindowPriority};
4#[cfg(feature = "window-list")]
5use libobs_window_helper::{get_all_windows, WindowInfo, WindowSearchMode};
6use libobs_wrapper::{
7    data::{ObsObjectBuilder, ObsObjectUpdater},
8    scenes::ObsSceneRef,
9    sources::{ObsSourceBuilder, ObsSourceRef},
10    utils::ObsError,
11};
12use num_traits::ToPrimitive;
13
14define_object_manager!(
15    /// Provides an easy-to-use builder for the window capture source.
16    #[derive(Debug)]
17    struct WindowCaptureSource("window_capture") for ObsSourceRef {
18
19    /// Sets the priority of the window capture source.
20    /// Used to determine in which order windows are searched for.
21    ///
22    /// # Arguments
23    ///
24    /// * `priority` - The priority of the window capture source.
25    ///
26    /// # Returns
27    ///
28    /// The updated `WindowCaptureSourceBuilder` instance.
29    #[obs_property(type_t = "enum")]
30    priority: ObsWindowPriority,
31
32    /// Sets the window to capture.
33    ///
34    /// # Arguments
35    ///
36    /// * `window` - The window to capture, represented as `ObsString`. Must be in the format of an obs window id
37    ///
38    /// # Returns
39    ///
40    /// The updated `WindowCaptureSourceBuilder` instance.
41    #[obs_property(type_t = "string", settings_key = "window")]
42    window_raw: String,
43
44    #[obs_property(type_t = "bool")]
45    /// Sets whether the cursor should be captured
46    cursor: bool,
47
48    #[obs_property(type_t = "bool")]
49    /// Whether to capture audio from window source (BETA) <br>
50    /// When enabled, creates an "Application Audio Capture" source that automatically updates to the currently captured window/application. <br>
51    /// Note that if Desktop Audio is configured, this could result in doubled audio.
52    capture_audio: bool,
53
54    #[obs_property(type_t = "bool")]
55    /// Whether to force SDR color space for the window capture source.
56    force_sdr: bool,
57
58    #[obs_property(type_t = "bool")]
59    /// Whether to capture the window's client area only (without borders, title bar and the main menu bar).
60    client_area: bool,
61
62    #[obs_property(type_t = "bool")]
63    compatibility: bool,
64
65    capture_method: Option<ObsWindowCaptureMethod>,
66});
67
68#[cfg(feature = "window-list")]
69#[libobs_simple_macro::obs_object_impl]
70impl WindowCaptureSource {
71    /// Gets a list of windows that can be captured by this source.
72    pub fn get_windows(
73        mode: WindowSearchMode,
74    ) -> anyhow::Result<Vec<libobs_wrapper::unsafe_send::Sendable<WindowInfo>>> {
75        Ok(get_all_windows(mode)?
76            .into_iter()
77            .map(libobs_wrapper::unsafe_send::Sendable)
78            .collect())
79    }
80
81    /// Sets the window to capture.
82    ///
83    /// # Arguments
84    ///
85    /// * `window` - The window to capture. A list of available windows can be retrieved using `WindowCaptureSourceBuilder::get_windows`
86    ///
87    /// # Returns
88    ///
89    /// The updated `WindowCaptureSourceBuilder` instance.
90    pub fn set_window(self, window: &libobs_wrapper::unsafe_send::Sendable<WindowInfo>) -> Self {
91        self.set_window_raw(window.0.obs_id.as_str())
92    }
93}
94
95impl<'a> WindowCaptureSourceUpdater<'a> {
96    pub fn set_capture_method(mut self, method: ObsWindowCaptureMethod) -> Self {
97        self.get_settings_updater()
98            .set_int_ref("method", method.to_i32().unwrap() as i64);
99
100        self
101    }
102}
103
104impl WindowCaptureSourceBuilder {
105    /// Sets the capture method for the window capture source.
106    pub fn set_capture_method(mut self, method: ObsWindowCaptureMethod) -> Self {
107        self.capture_method = Some(method);
108        self
109    }
110}
111
112impl ObsSourceBuilder for WindowCaptureSourceBuilder {
113    fn add_to_scene(mut self, scene: &mut ObsSceneRef) -> Result<ObsSourceRef, ObsError>
114    where
115        Self: Sized,
116    {
117        // Because of a black screen bug, we need to set the method to WGC first and then update (I've copied this code from the DisplayCapture source, they should have the same issue)
118        self.get_settings_updater().set_int_ref(
119            "method",
120            ObsWindowCaptureMethod::MethodAuto.to_i32().unwrap() as i64,
121        );
122
123        let method_to_set = self.capture_method;
124        let runtime = self.runtime.clone();
125
126        let b = self.build()?;
127        let mut res = scene.add_source(b)?;
128
129        if let Some(method) = method_to_set {
130            WindowCaptureSourceUpdater::create_update(runtime, &mut res)?
131                .set_capture_method(method)
132                .update()?;
133        }
134
135        Ok(res)
136    }
137}